#pragma once

#include "IActiveObject.h"
#include "EndpointMap.h"

namespace RoomFW {

class ActiveObject;

//
// Class:	ActiveObjectContainer
//
// Description:	Looks like an Active Object, but really just contains other Active Objects.
//				It has "relay ports" that forward to/from contained Active Objects.
//
// Author:	Andrew Sage
//
class ActiveObjectContainer : public virtual IActiveObject
{
public:

	//
	// Method:	ActiveObjectContainer
	//
	// Description:	Constructor
	//
	// Parameters:
	//
	//	portCount - Number of Port this object has.
	//
	ActiveObjectContainer(size_t portCount);

	//
	// Method:	~ActiveObjectContainer
	//
	// Description:	Destructor
	//
	virtual ~ActiveObjectContainer(void);

	//
	// Thread wrappers.  Calls corresponding method on children.
	// If timeout is not INFINITE, divided by number of children
	// before being passed to each child.
	//
	virtual bool start(uint32_t timeout = INFINITE);
	virtual bool stop(uint32_t timeout = INFINITE);
	virtual bool wait(uint32_t timeout = INFINITE);
	virtual bool isRunning(uint32_t timeout = 0);
	typedef bool (IActiveObject::*AOWait)(uint32_t timeout);
	bool childListWait(AOWait fn, uint32_t timeout);

	//
	// Thread overrides.  Not implemented.
	//
	virtual void main(void) { ASSERT(FALSE); }
	virtual void signalStop(void) { ASSERT(FALSE); }
	virtual bool isErrored();
	virtual std::string errorMessage();
	virtual ErrorHandling::IErrorSP getError();

	//
	// IActiveObject overrides
	//
	virtual IEndPointSP getEndPoint(PortIndex::PrimaryIndex portIndex);
	virtual bool setEndPoint(PortIndex& portIndex, IEndPointSP endPoint);
	virtual bool clearEndPoint(const PortIndex& portIndex);
	virtual void put(RoomMessageSP message);

protected:

	//
	// Class:	InnerWall
	//
	// Description:	Provides interface for "relay ports".
	//
	// Author:	Andrew Sage
	//
	class InnerWall : public IActiveObject
	{
	public:
		InnerWall(void);
		~InnerWall(void);
		void setOwner(ActiveObjectContainer* owner);

		virtual const char* getObjectName(void) const { return owner_->getObjectName(); }
		virtual const char* getPortName(size_t portIndex) const { return owner_->getPortName(portIndex); }
		virtual IEndPointSP getEndPoint(PortIndex::PrimaryIndex portIndex);
		virtual bool setEndPoint(PortIndex& portIndex, IEndPointSP endPoint);
		virtual bool clearEndPoint(const PortIndex& portIndex);
		virtual IContractCheckerSPC getContractChecker(PortIndex portIndex) const;

	protected:

		//
		// Thread overrides.
		//
		virtual void main(void) { ASSERT(FALSE); }
		virtual void signalStop(void) { ASSERT(FALSE); }

		//
		// Active Object override.
		//
		virtual void put(RoomMessageSP message);

	private:

		ActiveObjectContainer* owner_;
	};

	//
	// IActiveObject override.  Not implemented.
	//
	virtual void handle(RoomMessageSP message) { ASSERT(false); }

	//
	// Used by inner wall to bind a relay port to a child port.
	//
	virtual IEndPointSP getInnerWallEndPoint(PortIndex::PrimaryIndex portIndex);
	virtual bool setInnerWallEndPoint(PortIndex& portIndex, IEndPointSP endPoint);

	//
	// Used to get or set endpoints from specified map.
	//
	virtual IEndPointSP getEndPoint(EndpointMap& endpoints, PortIndex::PrimaryIndex portIndex, bool innerWall);
	virtual bool setEndPoint(EndpointMap& endpoints, PortIndex& portIndex, IEndPointSP endPoint);

	//
	// Used by inner wall to un-bind a relay port from a child port.
	//
	virtual bool clearInnerWallEndPoint(PortIndex portIndex);

	//
	// Used by inner wall to send a message from this object.
	//
	void sendMessage(PortIndex portIndex, MessageID messageID, IPayloadSP payload, const char* senderName, IEndPointSP replyEndpoint) const
		throw (SendMessageError);

	//
	// Derived classes should add children to support thread operations.
	//
	void addChild(IActiveObjectSP child) { childList_.push_back(child); }

	//
	// Derived classes should call to allow destruction of children.
	//
	void removeChild(IActiveObjectSP child);

	//
	// Derived classes should call from thier destructors.
	//
	void clearChildList(void) { childList_.clear(); }

	//
	// Accessor
	//
	IActiveObjectSP getInnerWall(void);

private:

	//
	// Interface for relay ports.
	//
	InnerWall innerWall_;

	//
	// End points pointing to child objects.
	//
	EndpointMap inEndPointMap_;
	EndpointMap inReplyEndPointMap_;

	//
	// End points pointing to external objects.
	//
	EndpointMap outEndPointMap_;
	EndpointMap outReplyEndPointMap_;

	//
	// Child object list.  Used by thread wrappers.
	//
	typedef std::list<IActiveObjectSP> ChildList;
	ChildList childList_;

	//
	// Not designed to be copied.
	//
	ActiveObjectContainer(const ActiveObjectContainer&);
	ActiveObjectContainer& operator =(const ActiveObjectContainer&);
};

}
